package club.xyes.zkh.ecommerce.wechat.service.impl;

import club.xyes.zkh.ecommerce.commons.entity.Shop;
import club.xyes.zkh.ecommerce.commons.util.DateTimeUtil;
import club.xyes.zkh.ecommerce.wechat.dto.SaoBeiJsPayResult;
import club.xyes.zkh.ecommerce.wechat.dto.SaoBeiPayResult;
import club.xyes.zkh.ecommerce.wechat.dto.SaoBeiRefundResult;
import club.xyes.zkh.ecommerce.wechat.dto.TradeQueryResult;
import club.xyes.zkh.ecommerce.wechat.service.SaoBeiService;
import club.xyes.zkh.ecommerce.wechat.service.prop.SaoBeiProperties;
import club.xyes.zkh.ecommerce.wechat.util.HttpUtil;
import club.xyes.zkh.ecommerce.wechat.util.Md5SignUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Create by 郭文梁 2019/4/19 0019 13:25
 * SaoBeiServiceImpl
 * 扫呗相关接口实现
 *
 * @author 郭文梁
 * @data 2019/4/19 0019
 */
@Service
@Slf4j
public class SaoBeiServiceImpl implements SaoBeiService {
    private static final int MIN_AMOUNT = 1;
    private static final String DATE_TIME_FORMAT = "yyyyMMddHHmmss";
    private static final String API_BASE_URL = "https://pay.lcsw.cn/lcsw";
    private static final String MICRO_PROGRAM_PAY_URL = API_BASE_URL + "/pay/100/minipay";
    private static final String TRADE_QUERY_URL = API_BASE_URL + "/pay/100/query";
    private static final String REFUND_URL = API_BASE_URL + "/pay/100/refund";
    private final SaoBeiProperties saoBeiProperties;

    @Autowired
    public SaoBeiServiceImpl(SaoBeiProperties saoBeiProperties) {
        this.saoBeiProperties = saoBeiProperties;
    }

    @Override
    public SaoBeiPayResult microProgramPay(String openId, int fee, String tradeNo, Shop shop) throws IOException {
        fee = fee <= 0 ? MIN_AMOUNT : fee;
        Map<String, String> params = microProgramPayParam(openId, fee, tradeNo, shop);
        signMicroProgramParam(params, shop.getAccessToken());
        String jsonBody = JSON.toJSONString(params);
        log.debug("Prepay post json [{}]", jsonBody);
        String res = HttpUtil.postJson(MICRO_PROGRAM_PAY_URL, jsonBody);
        return SaoBeiPayResult.fromJsonString(res);
    }

    @Override
    public TradeQueryResult query(String tradeNo, String outTradeNo, Shop shop) throws IOException {
        Map<String, String> param = tradeQueryParam(tradeNo, outTradeNo, shop);
        signTradeQueryParam(param, shop.getAccessToken());
        String jsonBody = JSON.toJSONString(param);
        String res = HttpUtil.postJson(TRADE_QUERY_URL, jsonBody);
        return TradeQueryResult.fromJsonString(res);
    }

    @Override
    public SaoBeiRefundResult refund(String tradeNo, int fee, String traceNo, Shop shop) throws IOException {
        Map<String, String> param = refundParam(tradeNo, fee, traceNo, shop);
        signRefundParam(param, shop.getAccessToken());
        String jsonBody = JSON.toJSONString(param);
        log.debug("Refund post body [{}]", jsonBody);
        String resp = HttpUtil.postJson(REFUND_URL, jsonBody);
        log.debug("Refund response {}", resp);
        return SaoBeiRefundResult.fromJson(resp);
    }

    @Override
    public SaoBeiJsPayResult jsPay(String tradeNo, int fee, Shop shop) {
        Map<String, String> params = new HashMap<>();
        return null;
    }

    private Map<String, String> jsPayParams(Shop shop, String tradeNo) {
        Map<String, String> params = new HashMap<>();
        params.put("pay_ver", saoBeiProperties.getPayVer());
        params.put("pay_type", "020");
        params.put("service_id", saoBeiProperties.getServiceId());
        params.put("merchant_no", shop.getMerchantNo());
        params.put("terminal_id", shop.getTerminalId());
        params.put("terminal_trace", tradeNo);
        return params;
    }

    /**
     * 打包退款请求参数
     *
     * @param tradeNo 交易号
     * @param fee     退款金额
     * @param traceNo 退款交易号
     * @return Map
     */
    private Map<String, String> refundParam(String tradeNo, int fee, String traceNo, Shop shop) {
        String datetime = DateTimeUtil.format(DateTimeUtil.now(), DATE_TIME_FORMAT);
        Map<String, String> param = new HashMap<>(11);
        param.put("pay_ver", saoBeiProperties.getPayVer());
        param.put("pay_type", saoBeiProperties.getPayType());
        param.put("service_id", saoBeiProperties.getServiceId());
        param.put("merchant_no", shop.getMerchantNo());
        param.put("terminal_id", shop.getTerminalId());
        param.put("terminal_trace", traceNo);
        param.put("terminal_time", datetime);
        param.put("refund_fee", String.valueOf(fee));
        param.put("out_trade_no", tradeNo);
        return param;
    }

    /**
     * 交易查询参数
     *
     * @param tradeNo    交易号
     * @param outTradeNo 扫呗订单号
     * @param shop       Shop
     * @return 查询结果
     */
    private Map<String, String> tradeQueryParam(String tradeNo, String outTradeNo, Shop shop) {
        Map<String, String> param = new HashMap<>(9);
        param.put("pay_ver", saoBeiProperties.getPayVer());
        param.put("pay_type", saoBeiProperties.getPayType());
        param.put("service_id", saoBeiProperties.getServiceId());
        param.put("merchant_no", shop.getMerchantNo());
        param.put("terminal_id", shop.getTerminalId());
        param.put("terminal_time", DateTimeUtil.format(DateTimeUtil.now(), DATE_TIME_FORMAT));
        param.put("out_trade_no", tradeNo);
        param.put("terminal_trace", outTradeNo);
        return param;
    }

    /**
     * 微信小程序支付参数
     *
     * @param openId  OPENID
     * @param fee     金额
     * @param orderNo 订单号
     * @param shop    商铺信息
     * @return 参数
     */
    private Map<String, String> microProgramPayParam(String openId,
                                                     Integer fee,
                                                     String orderNo,
                                                     Shop shop) {
        Map<String, String> param = new HashMap<>(11);
        param.put("pay_ver", saoBeiProperties.getPayVer());
        param.put("merchant_no", shop.getMerchantNo());
        param.put("service_id", saoBeiProperties.getServiceId());
        param.put("pay_type", saoBeiProperties.getPayType());
        param.put("terminal_id", shop.getTerminalId());
        param.put("terminal_trace", orderNo);
        param.put("terminal_time", DateTimeUtil.format(DateTimeUtil.now(), DATE_TIME_FORMAT));
        param.put("total_fee", String.valueOf(fee));
        param.put("open_id", openId);
        param.put("notify_url", saoBeiProperties.getNotifyUrl());
        param.put("sub_appid", saoBeiProperties.getSubAppId());
        return param;
    }

    /**
     * 对交易查询参数签名
     *
     * @param params      参数
     * @param accessToken 令牌
     */
    private void signTradeQueryParam(Map<String, String> params, String accessToken) {
        String sign = Md5SignUtil.signTradeQueryParam(params, accessToken);
        params.put("key_sign", sign);
    }

    /**
     * 参数签名
     *
     * @param accessToken 令牌
     * @param params      参数
     */
    private void signMicroProgramParam(Map<String, String> params, String accessToken) {
        String sign = Md5SignUtil.signMicroProgramParam(params, accessToken);
        params.put("key_sign", sign);
    }

    /**
     * 签名退款参数
     *
     * @param param       参数
     * @param accessToken 令牌
     */
    private void signRefundParam(Map<String, String> param, String accessToken) {
        String sign = Md5SignUtil.signRefundParam(param, accessToken);
        param.put("key_sign", sign);
    }
}
